﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;

namespace YoucaiReader.Helper.Drawing
{
    public class GraphicsImpl : Graphics
    {
        protected Color bgColor;
        private Canvas canvas;
        private Rect currentClip;
        private Font currentFont;
        private AffineTransformImpl currentTransformation;
        private SolidColorBrush fgBrush;
        private Color fgColor;
        public static object InvertTag = "Highlight";
        private int offscreenCanvasHeight;
        private int offscreenCanvasWidth;

        public GraphicsImpl()
        {
            this.currentColor = Colors.White;
            this.offscreenCanvasWidth = 0;
            this.offscreenCanvasHeight = 0;
            this.currentTransformation = new AffineTransformImpl();
            this.currentFont = FontFactoryImpl.Instance.getFont(FontFactoryImpl.Instance.getDefaultFamilyName(), FontFactoryImpl.Instance.getDefaultFontSize(), false, false, false);
        }

        public GraphicsImpl(int width, int height)
        {
            this.currentColor = Colors.White;
            this.offscreenCanvasWidth = width;
            this.offscreenCanvasHeight = height;
            this.RenderTransform = new AffineTransformImpl();
        }

        public virtual void BeginBatchDrawing()
        {
            this.canvas.Children.Clear();
        }

        //private static Image CloneImage(Image original)
        //{
        //    Image image = new Image();
        //    image.set_Source(original.get_Source());
        //    image.Width = (original.get_Width());
        //    image.Height = (original.get_Height());
        //    image.Opacity = (original.get_Opacity());
        //    image.set_RenderTransform(original.get_RenderTransform());
        //    image.set_Clip(original.get_Clip());
        //    return image;
        //}
        private static System.Windows.Controls.Image CloneImage(System.Windows.Controls.Image original)
        {
            System.Windows.Controls.Image image = new System.Windows.Controls.Image()
            {
                Source = original.Source,
                Width = original.Width,
                Height = original.Height,
                Opacity = original.Opacity,
                RenderTransform = original.RenderTransform,
                Clip = original.Clip
            };
            return image;
        }

        private void doArc(int x, int y, int width, int height, int startAngle, int arcAngle, Brush fill, Brush stroke)
        {
            Path element = new Path();
            EllipseGeometry geometry2 = new EllipseGeometry();
            geometry2.Center = (new Point((double)(width >> 1), (double)(height >> 1)));
            geometry2.RadiusX = ((double)(width >> 1));
            geometry2.RadiusY = ((double)(height >> 1));
            EllipseGeometry geometry = geometry2;
            element.Fill = (fill);
            element.Stroke = (stroke);
            element.Data = (geometry);
            this.Render(element, (double)x, (double)y);
        }

        public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle)
        {
            this.doArc(x, y, width, height, startAngle, arcAngle, null, new SolidColorBrush(this.fgColor));
        }

        public void drawBufferedImage(BufferedImage bufferedImage, int x, int y)
        {
            UIElement element = ((BufferedImageImpl)bufferedImage).getUIElement(this.Clip);
            this.Render(element, (double)x, (double)y);
        }

        public void drawImage(Image image, int x, int y)
        {
            this.Render(((ImageImpl)image).SilverlightImage, (double)x, (double)y);
        }

        //public void drawImage(Image image, int x, int y)
        //{
        //    Image element = (image.Parent != null) ? CloneImage(image) : image;
        //    this.Render(element, (double)x, (double)y);
        //}

        public void drawImage(System.Windows.Controls.Image image, int x, int y)
        {
            this.Render((image.Parent != null ? GraphicsImpl.CloneImage(image) : image), (double)x, (double)y);
        }

        public void drawLine(int x1, int y1, int x2, int y2)
        {
            Polyline polyline2 = new Polyline();
            polyline2.Points.Add(new Point((double)x1, (double)y1));
            polyline2.Points.Add(new Point((double)x2, (double)y2));
            polyline2.Stroke = (this.currentColorBrush);
            Polyline element = polyline2;
            this.Render(element, 0.0, 0.0);
        }

        //public void drawRect(int x, int y, int width, int height)
        //{
        //    Rectangle rectangle2 = new Rectangle();
        //    rectangle2.Stroke = (this.currentColorBrush);
        //    rectangle2.Height = ((double)(height + 1));
        //    rectangle2.Width = ((double)(width + 1));
        //    Rectangle element = rectangle2;
        //    this.Render(element, (double)x, (double)y);
        //}
        public void drawRect(int x, int y, int width, int height)
        {
            System.Windows.Shapes.Rectangle rectangle = new System.Windows.Shapes.Rectangle()
            {
                Stroke = this.currentColorBrush,
                Height = (double)(height + 1),
                Width = (double)(width + 1)
            };
            this.Render(rectangle, (double)x, (double)y);
        }

        public void drawText(char[] text, float x, float y, int width)
        {
            TextBlock block2 = new TextBlock();
            block2.Text = (new string(text, 0, text.Length));
            block2.FontSize = (22.0);
            TextBlock element = block2;
            this.Render(element, (double)x, (double)y);
        }

        public void drawText(char[] text, int offset, int length, int x, int y, int width)
        {
            TextBlock block2 = new TextBlock();
            block2.Text = (new string(text, offset, length));
            block2.Style = (((FontImpl)this.currentFont).getStyle());
            block2.Foreground = (this.currentColorBrush);
            TextBlock element = block2;
            this.Render(element, (double)x, (double)y);
        }

        public void drawText(string text, float x, float y, int width, int fontSize, SolidColorBrush fontColor)
        {
            TextBlock block2 = new TextBlock();
            block2.Text = (text);
            block2.FontSize = ((double)fontSize);
            block2.FontFamily = (new FontFamily("Arial"));
            block2.Foreground = (fontColor);
            TextBlock element = block2;
            this.Render(element, (double)x, (double)y);
        }

        public virtual void EndBatchDrawing()
        {
        }

        public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle)
        {
            this.doArc(x, y, width, height, startAngle, arcAngle, new SolidColorBrush(this.fgColor), null);
        }

        public void fillPath(GeneralPath gpath)
        {
            Path element = ((GeneralPathImpl)gpath).getPath();
            element.Fill = (this.currentColorBrush);
            this.Render(element, 0.0, 0.0);
        }

        public void fillPolygon(Polygon polygon)
        {
            this.Render(((PolygonImpl)polygon).Polygon, 0.0, 0.0);
        }

        //public void fillRect(int x, int y, int width, int height)
        //{
        //    Rectangle rectangle2 = new Rectangle();
        //    rectangle2.Fill = (this.currentColorBrush);
        //    rectangle2.Height = ((double)height);
        //    rectangle2.Width = ((double)width);
        //    Rectangle element = rectangle2;
        //    this.Render(element, (double)x, (double)y);
        //}

        public void fillRect(int x, int y, int width, int height)
        {
            System.Windows.Shapes.Rectangle rectangle2 = new System.Windows.Shapes.Rectangle();
            rectangle2.Fill = (this.currentColorBrush);
            rectangle2.Height = ((double)height);
            rectangle2.Width = ((double)width);
            System.Windows.Shapes.Rectangle element = rectangle2;
            this.Render(element, (double)x, (double)y);
        }

        public int getColor()
        {
            int num = 0;
            num = this.fgColor.A << 0x18;
            num |= this.fgColor.R << 0x10;
            num |= this.fgColor.G << 8;
            return (num | this.fgColor.B);
        }

        public Font getFont()
        {
            return this.currentFont.derive(this.currentFont.getSize());
        }

        public void invert(int x, int y, int width, int height)
        {
            this.invert(x, y, width, height, -16731984);
        }

        //protected void invert(int x, int y, int width, int height, int color)
        //{
        //    int rgb = this.getColor();
        //    this.setColor(color);
        //    Rectangle rectangle2 = new Rectangle();
        //    rectangle2.Height = ((double)height);
        //    rectangle2.Width = ((double)width);
        //    rectangle2.Fill = (this.currentColorBrush);
        //    rectangle2.Opacity = (0.5);
        //    Rectangle element = rectangle2;
        //    this.Render(element, (double)x, (double)y);
        //    this.setColor(rgb);
        //    if (this.IsOnScreen)
        //    {
        //        element.Tag = (InvertTag);
        //    }
        //}

        protected void invert(int x, int y, int width, int height, int color)
        {
            int num = this.getColor();
            this.setColor(color);
            System.Windows.Shapes.Rectangle rectangle = new System.Windows.Shapes.Rectangle()
            {
                Height = (double)height,
                Width = (double)width,
                Fill = this.currentColorBrush,
                Opacity = 0.5
            };
            System.Windows.Shapes.Rectangle invertTag = rectangle;
            this.Render(invertTag, (double)x, (double)y);
            this.setColor(num);
            if (this.IsOnScreen)
            {
                invertTag.Tag = GraphicsImpl.InvertTag;
            }
        }

        private void RemoveCanvasParent(Canvas c)
        {
            if (c.Parent != null)
            {
                Canvas canvas = c.Parent as Canvas;
                if (canvas != null)
                {
                    canvas.Children.Remove(c);
                }
            }
        }

        protected void Render(UIElement element, double left, double top)
        {
            Canvas.SetLeft(element, left);
            Canvas.SetTop(element, top);
            if (element is Canvas)
            {
                this.RemoveCanvasParent((Canvas)element);
            }
            if (!this.RenderTransform.IsIdentity)
            {
                element.RenderTransform = (this.RenderTransform.Value);
            }
            if ((this.Clip.Width > 0.0) && (this.Clip.Height > 0.0))
            {
                RectangleGeometry geometry2 = new RectangleGeometry();
                geometry2.Rect = (this.Clip);
                RectangleGeometry geometry = geometry2;
                element.Clip = (geometry);
            }
            this.FrameBuffer.Children.Add(element);
        }

        public void setColor(int rgb)
        {
            Color color = Color.FromArgb(0xff, (byte)((rgb & 0xff0000) >> 0x10), (byte)((rgb & 0xff00) >> 8), (byte)(rgb & 0xff));
            this.currentColor = color;
        }

        public void setFont(Font font)
        {
            this.currentFont = font;
        }

        internal int BackgroundColor
        {
            get
            {
                int num = 0;
                num = this.bgColor.A << 0x18;
                num |= this.bgColor.R << 0x10;
                num |= this.bgColor.G << 8;
                return (num | this.bgColor.B);
            }
        }

        internal Rect Clip
        {
            get
            {
                return this.currentClip;
            }
            set
            {
                this.currentClip = value;
            }
        }

        protected Color currentColor
        {
            get
            {
                return this.fgColor;
            }
            set
            {
                if (this.fgColor != value)
                {
                    this.fgColor = value;
                    this.fgBrush = null;
                }
            }
        }

        private SolidColorBrush currentColorBrush
        {
            get
            {
                if (this.fgBrush == null)
                {
                    this.fgBrush = new SolidColorBrush(this.fgColor);
                }
                return this.fgBrush;
            }
        }

        public Canvas FrameBuffer
        {
            internal get
            {
                if (((this.canvas == null) && (this.offscreenCanvasWidth != 0)) && (this.offscreenCanvasHeight != 0))
                {
                    this.canvas = new Canvas();
                    this.canvas.Width = ((double)this.offscreenCanvasWidth);
                    this.canvas.Height = ((double)this.offscreenCanvasHeight);
                }
                return this.canvas;
            }
            set
            {
                this.canvas = value;
            }
        }

        internal int Height
        {
            get
            {
                if (this.canvas != null)
                {
                    return (int)this.canvas.Height;
                }
                return this.offscreenCanvasHeight;
            }
        }

        protected bool IsOnScreen
        {
            get
            {
                return (((this.canvas != null) && (this.offscreenCanvasWidth == 0)) && (this.offscreenCanvasHeight == 0));
            }
        }

        internal AffineTransformImpl RenderTransform
        {
            get
            {
                return new AffineTransformImpl(this.currentTransformation.Matrix);
            }
            set
            {
                this.currentTransformation = value;
            }
        }

        internal int Width
        {
            get
            {
                if (this.canvas != null)
                {
                    return (int)this.canvas.Width;
                }
                return this.offscreenCanvasWidth;
            }
        }
    }
}

